import random
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt


def cv_read():
    img = cv.imread("img/lena.jpg")
    img = img[200:300, 150:300]
    cv.imshow("src", img)


def image_img():
    """镜像"""
    img = cv.imread("img/lena.jpg")
    height = img.shape[0]
    width = img.shape[1]
    new_img = np.zeros((height * 2, width, 3), np.uint8)

    for row in range(height):
        for col in range(width):
            # 上半部
            new_img[row, col] = img[row, col]
            # 下半部
            new_img[height + row, col] = img[height - row - 1, col]

    cv.imshow("new_img", new_img)


def resize_pic():
    """图片缩放"""
    img = cv.imread("img/lena.jpg", cv.IMREAD_COLOR)
    img_info = img.shape
    height = img_info[0]
    width = img_info[1]
    new_img = cv.resize(img, (int(width / 2), int(height / 2)), fx=20, fy=20)
    cv.imshow("resize", new_img)


def scale_img():
    """缩放图片"""
    img = cv.imread("img/lena.jpg", cv.IMREAD_COLOR)
    cv.imshow("img", img)
    img_shape = img.shape
    height = img_shape[0]
    width = img_shape[1]

    matrix_scale = np.array([[0.5, 0, 0],
                             [0, 0.5, 0]])
    new_img = cv.warpAffine(img, np.float32(matrix_scale), (width, height))
    cv.imshow("new_img", new_img)


def shift_img():
    """图片平移"""
    # 平移原点
    origin_coordinate = (50, 40)

    img = cv.imread("img/lena.jpg", cv.IMREAD_COLOR)
    cv.imshow("img", img)
    img_shape = img.shape
    height = img_shape[0]
    width = img_shape[1]

    matrix_shift = np.array([[1, 0, origin_coordinate[0]],
                             [0, 1, origin_coordinate[1]]
                             ])
    new_img = cv.warpAffine(img, np.float32(matrix_shift), (width, height))
    cv.imshow("new_img", new_img)


def revolve_img():
    """旋转照片"""
    img = cv.imread("img/lena.jpg", cv.IMREAD_COLOR)
    img_info = img.shape
    height = img_info[0]
    width = img_info[1]

    # 旋转中心
    revolve_center = (width / 2, height / 2)
    matrix_revolve = cv.getRotationMatrix2D(revolve_center, 45, 1)
    new_img = cv.warpAffine(img, matrix_revolve, (width, height))
    cv.imshow("new_img", new_img)


def affine_pic():
    """仿射变换"""
    img = cv.imread("img/lena.jpg", cv.IMREAD_COLOR)
    img_info = img.shape
    height = img_info[0]
    width = img_info[1]
    # 初始的图片的三个点
    matrix_dst = np.float32([[0, 0], [0, height - 1], [width - 1, 0]])
    # 变换后图片的三个点
    # matrix_src = np.float32([[50, 100], [300, height - 200], [width - 300, 100]])
    matrix_src = np.float32([[50, 50], [50, 100], [100, 50]])
    matrix_affine = cv.getAffineTransform(matrix_src, matrix_dst)
    affine_img = cv.warpAffine(img, matrix_affine, (width, height))
    cv.imshow("affine_img", affine_img)


def pyr_pic():
    """改变采样分辨率"""
    img = cv.imread("img/lena.jpg", cv.IMREAD_COLOR)
    img_info = img.shape
    height = img_info[0]
    width = img_info[1]

    pry_down1_img = cv.pyrDown(img)
    cv.imshow("pry_down1_img", pry_down1_img)
    pry_down2_img = cv.pyrDown(pry_down1_img)
    cv.imshow("pry_down2_img", pry_down2_img)
    pry_down3_img = cv.pyrDown(pry_down2_img)
    cv.imshow("pry_down3_img", pry_down3_img)
    pry_down4_img = cv.pyrDown(pry_down3_img)
    cv.imshow("pry_down4_img", pry_down4_img)


def overlying_pic():
    """图像融合"""
    img1 = cv.imread("img/yunduo.jpg", cv.IMREAD_COLOR)
    img2 = cv.imread("img/home.jpg", cv.IMREAD_COLOR)
    img1 = cv.resize(img1, (img2.shape[1], img2.shape[0]))
    overlying_img = cv.addWeighted(img1, 0.7, img2, 0.3, 0)
    cv.imshow("overlying_img", overlying_img)


def mosaic_pic():
    """将马赛克块区域的所有像素点替换为某个像素点"""
    # 马赛克块大小
    block_size = 4

    img = cv.imread("img/home.jpg", cv.IMREAD_COLOR)
    cv.imshow("img", img)

    img_info = img.shape
    height = img_info[0]
    width = img_info[1]

    for row in range(int(height / 3), height, block_size):
        for col in range(int(width / 3), width, block_size):
            (b, g, r) = img[row, col]
            # 切片
            img[row: row + block_size, col: col + block_size] = (b, g, r)

    cv.imshow("mosaic_img", img)


def vague_pic():
    """
    模糊效果
        从附近色块中，随机选择1个像素点值作为当前像素点的值
    :return:
    """
    img = cv.imread("img/home.jpg", cv.IMREAD_COLOR)
    cv.imshow("img", img)

    img_info = img.shape
    height = img_info[0]
    width = img_info[1]

    matrix_vague = np.zeros(img_info, np.uint8)

    # 指定偏移范围
    offset = 3

    for row in range(height):
        for col in range(width):
            dif = int(random.random() * offset)
            random_row = row + dif if row + dif < height else height - 1
            random_col = col + dif if col + dif < width else width - 1
            matrix_vague[row][col] = img[random_row][random_col]

    cv.imshow("vague_img", matrix_vague)


def contour_pic():
    """
    体现轮廓
        用相邻像素点的差值体现
    :return:
    """
    img = cv.imread("img/home.jpg", cv.IMREAD_COLOR)
    img_info = img.shape
    height = img_info[0]
    width = img_info[1]

    # 转成灰色图片 - 元素的颜色值编程了1位
    gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
    # gray_img = img

    # contour_img = np.zeros(img_info, np.uint8)
    contour_img = np.zeros_like(gray_img)

    for row in range(height):
        for col in range(width - 1):
            # 水平方向做差 - 水平梯度
            gray_0 = gray_img[row][col]
            gray_1 = gray_img[row][col + 1]

            # 计算新灰度
            gray = int(gray_0) - int(gray_1) + 120
            # b = int(gray_0[0]) - int(gray_1[0]) + 120
            # g = int(gray_0[1]) - int(gray_1[1]) + 120
            # r = int(gray_0[2]) - int(gray_1[2]) + 120

            # b = b if b <= 255 else 255
            # g = g if g <= 255 else 255
            # r = r if r <= 255 else 255
            # 校验越界
            if gray > 255:
                gray = 255
            if gray < 0:
                gray = 0

            contour_img[row][col] = gray
            # contour_img[row][col] = (b, g, r)

    cv.imshow("contour_img", contour_img)


def paint():
    """绘制图形"""
    matrix_img = np.zeros((500, 500, 3), np.uint8)

    # 绘制线段 - 参数2：起始点 参数3：结束点 参数4：颜色 参数5：线条宽度
    cv.line(matrix_img, (50, 10), (400, 10), (123, 123, 123), 10)
    # 抗锯齿
    cv.line(matrix_img, (50, 50), (400, 50), (123, 123, 123), 10, cv.LINE_AA)

    # 绘制矩形 - 参数2： 左上角  参数3：右下角 参数4：颜色  参数5：线条宽度，若为负数，则填充整个矩形
    cv.rectangle(matrix_img, (100, 100), (300, 300), (100, 200, 300), 5)

    # 绘制圆形 - 参数2：圆心  参数3：半径  参数4：颜色 参数5：线条宽度
    cv.circle(matrix_img, (200, 400), 100, (300, 200, 100), 5)

    cv.imshow("paint_img", matrix_img)


def paint_word():
    img = cv.imread("img/home.jpg", cv.IMREAD_COLOR)
    font = cv.FONT_HERSHEY_SIMPLEX
    # 参数2：文本 参数3：显示位置  参数4：字体 参数5：大小 参数6：颜色 参数7：粗细 参数8：线条类型
    cv.putText(img, "hello", (400, 500), font, 1, (0, 0, 255), 2, cv.LINE_AA)
    cv.imshow("img", img)


def lighten():
    """增强亮度"""
    img = cv.imread("img/home.jpg", cv.IMREAD_GRAYSCALE)
    cv.imshow("img", img)
    print(img.shape)
    new_img = img + 50
    new_img[new_img > 255] = 255
    cv.imshow("new_img", new_img)


def count_gray():
    """灰色图片直方图均衡化"""
    img = cv.imread("img/home.jpg", cv.IMREAD_COLOR)
    # lbxx_img = cv.imread("lbxx.jpg", cv.IMREAD_GRAYSCALE)
    # cv.imshow("lbxx_img", lbxx_img)

    gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
    cv.imshow("gray_img", gray_img)
    # 计算直方图 - 数组方式 传值 - 方式一
    # hist = cv.calcHist([gray_img], [0], None, [256], [0.0, 255.0])
    # plt.plot(hist, color="green")
    # plt.show()
    # 计算直方图 - 方式二
    plt.hist(gray_img.ravel(), color="red", bins=256)
    plt.hist(gray_img.ravel(), color="red", bins=256)
    plt.show()

    # 均衡化直方图
    equalize_img = cv.equalizeHist(gray_img)
    cv.imshow("equalize_img", equalize_img)


def count_color():
    """彩色图片直方图均衡化"""
    img = cv.imread("img/home.jpg", cv.IMREAD_COLOR)
    # 拆分出单个颜色
    b_img, g_img, r_img = cv.split(img)

    plt.hist(b_img.ravel(), color="red", bins=256)
    plt.show()
    # 均衡化b
    equalize_b_img = cv.equalizeHist(b_img)
    cv.imshow("equalize_b_img", equalize_b_img)

    plt.hist(g_img.ravel(), color="red", bins=256)
    plt.show()
    # 均衡化g
    equalize_g_img = cv.equalizeHist(g_img)
    cv.imshow("equalize_g_img", equalize_g_img)

    plt.hist(r_img.ravel(), color="red", bins=256)
    plt.show()
    # 均衡化r
    equalize_r_img = cv.equalizeHist(r_img)
    cv.imshow("equalize_r_img", equalize_r_img)

    # 合并颜色
    equalize_img = cv.merge([equalize_b_img, equalize_g_img, equalize_r_img])
    cv.imshow("img", img)
    cv.imshow("equalize_img", equalize_img)


def video_process():
    video = cv.VideoCapture("img/twotiger.avi")
    video = cv.VideoCapture(0)
    # 判断视频是否打开成功
    is_opened = video.isOpened()
    if not is_opened:
        return
    # 获取图片的信息:帧率
    fps = video.get(cv.CAP_PROP_FPS)
    # 获取每帧宽度
    width = video.get(cv.CAP_PROP_FRAME_WIDTH)
    # 获取每帧的高度
    height = video.get(cv.CAP_PROP_FRAME_HEIGHT)
    print("帧率：{},宽度：{},高度：{}".format(fps, width, height))

    while video.isOpened():
        res, img = video.read()
        if res:
            cv.imshow("img", img)
            cv.waitKey(int(1000/fps))


def color_filter():
    """颜色过滤"""
    bgr_img = cv.imread("img/tenis1.jpg", cv.IMREAD_COLOR)
    cv.imshow("rgb_img", bgr_img)

    # BGR颜色空间转化为HSV空间
    hsv_img = cv.cvtColor(bgr_img, cv.COLOR_BGR2HSV)

    # 定义颜色范围
    lower_color = (30, 120, 130)
    upper_color = (60, 255, 255)

    mask_img = cv.inRange(hsv_img, lower_color, upper_color)

    # 合成
    bgr_img[mask_img == 0] = (0, 0, 0)

    # 颜色范围内内容是白色，其它为黑色
    cv.imshow("mask_img", mask_img)
    cv.imshow("bgr_img", bgr_img)


def replace_img():
    img1 = cv.imread("img/yunduo.jpg", cv.IMREAD_COLOR)
    img2 = cv.imread("img/lion.jpg", cv.IMREAD_COLOR)

    img2_hsv = cv.cvtColor(img2, cv.COLOR_BGR2HSV)
    # 定义绿幕颜色范围
    lower_green = (35, 43, 60)
    upper_green = (77, 255, 255)

    # 选中绿幕 - 选中的地方变成白色(255)
    img2_green = cv.inRange(img2_hsv, lower_green, upper_green)
    cv.imshow("img2_green", img2_green)
    # 在BGR的原图中将绿幕变成黑色（0）
    img2[img2_green == 255] = (0, 0, 0)
    cv.imshow("img2", img2)
    # 将背景图的对应部分变为黑色
    img1[img2_green == 0] = (0, 0, 0)
    cv.imshow("img1", img1)
    # 两张图叠加
    new_img= img1 + img2
    cv.imshow("new_img", new_img)


def two_value_ize():
    """
    图像二值化
        THRESH_BINARY	高于阈值改为255,低于阈值改为0
        THRESH_BINARY_INV	高于阈值改为0,低于阈值改为255
        THRESH_TRUNC	截断,高于阈值改为阈值,最大值失效
        THRESH_TOZERO	高于阈值不改变,低于阈值改为0
        THRESH_TOZERO_INV	高于阈值该为0,低于阈值不改变
    """
    # 简单阈值
    # thresh = 100
    # img = cv.imread("img/thresh1.jpg", cv.IMREAD_GRAYSCALE)
    # ret, thresh_img = cv.threshold(img, thresh, 255, cv.THRESH_BINARY)
    # cv.imshow("thresh_img", thresh_img)

    # 自适应阈值
    """
    cv.ADAPTIVE_THRESH_MEAN_C：该阈值是该附近区域减去恒定的平均Ç。
    cv.ADAPTIVE_THRESH_GAUSSIAN_C：阈值是邻域值减去常数C的高斯加权和。
    """
    # img = cv.imread("img/thresh1.jpg", cv.IMREAD_GRAYSCALE)
    # # 直接调用api处理 参数1：图像数据 参数2：最大值  参数3：计算阈值的方法， 参数4：阈值类型 参数5：处理块大小  参数6：算法需要的常量C
    # adapt_thresh_img = cv.adaptiveThreshold(img, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 11, 5)
    # cv.imshow("adapt_thresh_img", adapt_thresh_img)

    # 最大类间方差法 - 大津法 - 可以去噪但如果很接近的颜色会识别不出来
    img = cv.imread("img/otsu_test.png", cv.IMREAD_GRAYSCALE)
    cv.imshow("img", img)
    gaussian_img = cv.GaussianBlur(img, (5, 5), 0)
    cv.imshow("gaussian_img", gaussian_img)
    ret, thresh_img = cv.threshold(gaussian_img, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
    cv.imshow("otsu", thresh_img)
    print("阈值", ret)


def average_filtering():
    """
    均值滤波
    G =1/9[
            [1, 1, 1],
            [1, 1, 1],
            [1, 1, 1],
            ]
    """
    img = cv.imread("img/otsu_test.png", cv.IMREAD_COLOR)
    cv.imshow("img", img)

    average_img = cv.blur(img, (3, 3))
    cv.imshow("average_img", average_img)


def gaussian_filtering():
    """
    高斯模糊
        高斯模糊通常被用来减少图像噪声以及降低细节层次
            G =1/16[
                    [1, 2, 1],
                    [2, 4, 2],
                    [1, 2, 1],
                    ]
    :return:
    """
    img = cv.imread("img/otsu_test.png", cv.IMREAD_GRAYSCALE)
    cv.imshow("img", img)

    def updateSigma(val):
        # 高斯模糊   参数1:图像  参数2:卷积核大小, 参数3:标准差越大，去除高斯噪声能力越强，图像越模糊
        gaussian_blur = cv.GaussianBlur(img, (5, 5), val)
        cv.imshow("gaussian_blur", gaussian_blur)

    # 创建一个窗口
    cv.namedWindow("gaussian", cv.WINDOW_AUTOSIZE)
    # 创建一个窗口进度条: 参数1:名称 参数2:窗口名称  参数3: 起始值  参数4: 最大值, 参数5:回调函数
    cv.createTrackbar("sigma", "gaussian", 0, 255, updateSigma)
    updateSigma(0)


def median_filtering():
    """
    中值滤波
    对邻近的像素点进行灰度排序,然后取中间值,它能有效去除图像中的椒盐噪声
    :return:
    """
    img = cv.imread("img/morph-opening.jpg", cv.IMREAD_GRAYSCALE)
    cv.imshow("img", img)

    median_img = cv.medianBlur(img, 5)
    cv.imshow("median_img", median_img)


def sobel():
    """
    Sobel算子是像素图像边缘检测中最重要的算子之一
    水平梯度
        Gx =[
            [-1, 0, 1],
            [-2, 0, 2],
            [-1, 0, 1],
            ]
    垂直梯度
        Gy =[
            [-1, -2, -1],
            [0, 0, 0],
            [1, 2, 1],
            ]
    合成
        G = 根号下 (Gx)^2 + (Gy)^2
        为了提高计算机效率我们通常会使用: G = |Gx|+|Gy|
    :return:
    """
    img = cv.imread("img/brain.jpg", cv.IMREAD_COLOR)
    cv.imshow("img", img)

    # sobel算子  参数1:图像, 参数2:图像的深度 -1表示和原图相同, 参数3: x方向求导的阶数 参数4: y方向求导的阶数
    # x_sobel = cv.Sobel(img, cv.CV_32F, 1, 0)
    x_sobel = cv.Sobel(img, -1, 1, 0)
    # 将图像转成8位int
    # x_sobel = cv.convertScaleAbs(x_sobel)

    cv.imshow("x_sobel", x_sobel)

    # sobel算子  参数1:图像, 参数2:图像的深度 -1表示和原图相同, 参数3: x方向求导的阶数 参数4: y方向求导的阶数
    # y_sobel = cv.Sobel(img, cv.CV_16S, 0, 1)
    y_sobel = cv.Sobel(img, -1, 0, 1)
    # 将图像转成8位int
    # y_sobel = cv.convertScaleAbs(y_sobel)

    cv.imshow("y_sobel", y_sobel)

    # x, y 叠加
    xy_sobel = cv.addWeighted(x_sobel, 0.5, y_sobel, 0.5, 0)
    cv.imshow("xy_sobel", xy_sobel)


def scharr():
    """sobel算子升级版"""
    img = cv.imread("img/brain.jpg", cv.IMREAD_COLOR)
    cv.imshow("img", img)

    # sobel算子  参数1:图像, 参数2:图像的深度 -1表示和原图相同, 参数3: x方向求导的阶数 参数4: y方向求导的阶数
    # x_scharr = cv.Scharr(img, cv.CV_32F, 1, 0)
    x_scharr = cv.Scharr(img, -1, 1, 0)
    # 将图像转成8位int
    # x_scharr = cv.convertScaleAbs(x_scharr)

    cv.imshow("x_scharr", x_scharr)

    # sobel算子  参数1:图像, 参数2:图像的深度 -1表示和原图相同, 参数3: x方向求导的阶数 参数4: y方向求导的阶数
    # y_scharr = cv.Scharr(img, cv.CV_16S, 0, 1)
    y_scharr = cv.Scharr(img, -1, 0, 1)
    # 将图像转成8位int - uint8
    # y_scharr = cv.convertScaleAbs(y_scharr)

    cv.imshow("y_scharr", y_scharr)

    # x, y 叠加
    xy_scharr = cv.addWeighted(x_scharr, 0.5, y_scharr, 0.5, 0)
    cv.imshow("xy_scharr", xy_scharr)


def laplacian():
    """
    拉普拉斯算子 - 使图像中小的细节部分得到增强
    普通
        G =[
            [0, 1, 0],
            [1, -4, 1],
            [0, 1, 0],
            ]
    增强型
        G =[
            [1, 1, 1],
            [1, -8, 1],
            [1, 1, 1],
            ]
    :return:
    """
    img = cv.imread("img/hehua.jpg", cv.IMREAD_COLOR)
    cv.imshow("img", img)

    # 使用拉普拉斯算子
    # laplacian_img = cv.Laplacian(img, cv.CV_32F)
    laplacian_img = cv.Laplacian(img, -1)
    # 取绝对值，将数据转到uint8类型
    # laplacian_img = cv.convertScaleAbs(laplacian_img)

    cv.imshow("laplacian_img", laplacian_img)


def canny():
    """
    canny边缘检测算法
    内部包含四个阶段
        1. 噪声抑制（通过Gaussianblur高斯模糊降噪）:使用5x5高斯滤波器去除图像中的噪声
        2. 查找边缘的强度及方向（通过Sobel滤波器）
        3. 应用非最大信号抑制（Non-maximum Suppression）: 完成图像的全扫描以去除可能不构成边缘的任何不需要的像素
        4. 高低阈值分离出二值图像（Hysteresis Thresholding）
          ○ 高低阈值比例为T2:T1 = 3:1 / 2:1
          ○ T2为高阈值，T1为低阈值
    :return:
    """
    img = cv.imread("img/shape.jpg", cv.IMREAD_COLOR)
    cv.imshow("img", img)

    # 转换灰度照片
    gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)

    # canny算法
    canny_img = cv.Canny(gray_img, 50, 180)

    cv.imshow("canny_img", canny_img)


def bilateral_filtering():
    """
    双边滤波
        双边滤波器可以很好的保存图像边缘细节而滤除掉低频分量的噪音，但是双边滤波器的效率不是太高，花费的时间相较于其他滤波器而言也比较长
    :return:
    """
    img = cv.imread("img/timg.jpg", cv.IMREAD_COLOR)
    cv.imshow("img", img)

    # 双边滤波
    """
    src: 输入图像 
    d: 表示在过滤过程中每个像素邻域的直径范围。如果这个值是非正数，则函数会从sigmaSpace计算该值。 
    sigmaColor: 颜色空间过滤器的sigma值，这个参数的值越大，表明该像素邻域内有越宽广的颜色会被混合到一起，产生较大的半相等颜色区域
    sigmaSpace: 坐标空间中滤波器的sigma值，如果该值较大，则意味着越远的像素将相互影响，从而使更大的区域中足够相似的颜色获取相同的颜色
    """
    bilateral_img = cv.bilateralFilter(img, 10, 50, 50)

    cv.imshow("bilateral_img", bilateral_img)


def sharpening_filtering():
    """
    锐化滤波
        图像的锐化和边缘检测很像，首先找到边缘，然后把边缘加到原来的图像上面，这样就强化了图像的边缘，使图像看起来更加锐利了
        滤波核
            G =[
                [-1, -1, -1],
                [-1, 9, -1],
                [-1, -1, -1],
                ]
        实际上是计算当前点和周围点的差别，然后将这个差别加到原来的位置上。另外，中间点的权值要比所有的权值和大于1，意味着这个像素要保持原来的值。
        按照公式来创建锐化滤波核:
            G =[
                [-k, -k, -k],
                [-k, 8K+1, -k],
                [-k, -k, -k],
                ]
    :return:
    """
    img = cv.imread("img/hehua.jpg", cv.IMREAD_COLOR)
    cv.imshow("img", img)

    kernel = np.array([
        [-1, -1, -1],
        [-1, 9, -1],
        [-1, -1, -1],
    ])
    sharpening_img = cv.filter2D(img, -1, kernel)

    cv.imshow("sharpening_img", sharpening_img)
    laplacian_img = cv.Laplacian(sharpening_img, -1)
    cv.imshow("laplacian_img", laplacian_img)
    laplac_img = cv.Laplacian(img, -1)
    cv.imshow("laplac_img", laplac_img)


def dilation():
    """
    # 膨胀： 用内核中最大的值填充当前像素点的值, 会去掉一些暗点，以及向外扩张
    1. 对象边缘增加一个像素
    2. 使对象边缘平滑
    3. 减少了对象与对象之间的距离
    :return:
    """
    img = cv.imread("img/morph-closing.jpg", cv.IMREAD_GRAYSCALE)
    cv.imshow("img", img)

    """
    结构元素的形状:
    MORPH_RECT	    矩形
    MORPH_ELLIPSE	椭圆形
    MORPH_CROSS	    十字型
    """
    kernel = cv.getStructuringElement(cv.MORPH_RECT, (5, 5))
    dilation_img = cv.dilate(img, kernel)
    cv.imshow("dilation_img", dilation_img)


def erosion():
    """
    腐蚀和膨胀过程类似,唯一不同的是以覆盖的最小值替换当前的像素值，会去掉一些亮点，以及向内腐蚀变细
    1. 对象边缘减少一个像素
    2. 对象边缘平滑
    3. 弱化了对象与对象之间连接
    """
    img = cv.imread("img/morph-opening.jpg", cv.IMREAD_GRAYSCALE)
    cv.imshow("img", img)

    kernel = cv.getStructuringElement(cv.MORPH_RECT, (5, 5))

    erosion_img = cv.erode(img, kernel)
    cv.imshow("erosion_img", erosion_img)


def opening():
    """
    开操作
        先腐蚀，后膨胀，主要应用在二值图像或灰度图像
        先腐蚀: 让当前窗口中最小的颜色值替换当前颜色值
        后膨胀: 让当前窗口中最大的颜色值替换当前颜色值
        1. 一般用于消除小的干扰或噪点（验证码图的干扰线）
        2. 可以通过此操作配合结构元素，提取图像的横线和竖线
    :return:
    """
    img = cv.imread("img/morph-opening.jpg", cv.IMREAD_GRAYSCALE)
    cv.imshow("img", img)

    kernel = cv.getStructuringElement(cv.MORPH_RECT, (5, 5))

    opening_img = cv.morphologyEx(img, cv.MORPH_OPEN, kernel)
    cv.imshow("opening_img", opening_img)


def closing():
    """
    闭操作
        先膨胀，后侵蚀
        一般用于填充内部缝隙
    :return:
    """
    img = cv.imread("img/morph-closing.jpg", cv.IMREAD_GRAYSCALE)
    cv.imshow("img", img)

    kernel = cv.getStructuringElement(cv.MORPH_RECT, (5, 5))

    closing_img = cv.morphologyEx(img, cv.MORPH_CLOSE, kernel)
    cv.imshow("dst", closing_img)


def distance_transfer():
    """
    距离变换:
    计算图像中每一个非零点距离自己最近的零点的距离，方法输出的信息为距离而不是颜色值，图像上越亮的点，
    代表了离零点的距离越远。可以用来细化轮廓，或者寻找物体的质心
    """
    img = cv.imread("img/coins.jpg", cv.IMREAD_GRAYSCALE)
    cv.imshow("img", img)

    # 二值化
    ret, thresh_img = cv.threshold(img, 0, 255, cv.THRESH_BINARY_INV | cv.THRESH_OTSU)
    cv.imshow("thresh_img", thresh_img)

    # 距离变换
    """
    DIST_L1	distance = |x1-x2| + |y1-y2|
    DIST_L2	the simple euclidean distance 勾股定理，欧氏距离
    DIST_C	distance = max(|x1-x2|,|y1-y2|)
    DIST_L12	L1-L2 metric: distance = 2(sqrt(1+x*x/2) - 1))
    DIST_FAIR	distance = c^2(|x|/c-log(1+|x|/c)), c = 1.3998
    DIST_WELSCH	distance = c^2/2(1-exp(-(x/c)^2)), c = 2.9846
    DIST_HUBER	distance = |x|<c ? x^2/2 : c(|x|-c/2), c=1.345
    """
    distance_img = cv.distanceTransform(thresh_img, cv.DIST_L2, 5)
    cv.imshow("distance_img", distance_img)
    # 标准化在0,1之间
    norm_img = cv.normalize(distance_img, 0, 1, norm_type=cv.NORM_MINMAX)
    cv.imshow("norm_img", norm_img)


if __name__ == "__main__":
    # cv_read()
    # image_img()
    # resize_pic()
    # shift_img()
    # revolve_img()
    # scale_img()
    # affine_pic()
    # pyr_pic()
    # overlying_pic()
    # mosaic_pic()
    # vague_pic()
    # contour_pic()
    # paint()
    # paint_word()
    # lighten()
    # count_gray()
    # count_color()
    # video_process()
    # color_filter()
    # replace_img()
    # two_value_ize()
    # average_filtering()
    # gaussian_filtering()
    # median_filtering()
    # sobel()
    # scharr()
    # laplacian()
    # canny()
    # bilateral_filtering()
    # sharpening_filtering()
    # dilation()
    # erosion()
    # closing()
    distance_transfer()

    # 让程序处于等待推出状态
    cv.waitKey(0)
    # 当程序推出时，释放所有窗口资源
    cv.destroyAllWindows()




